package lol.clann.minecraft.springboot.plugin.core.config.jackson.deserializer;

import relocate.com.fasterxml.jackson.core.JsonParser;
import relocate.com.fasterxml.jackson.core.JsonProcessingException;
import relocate.com.fasterxml.jackson.databind.DeserializationContext;
import relocate.com.fasterxml.jackson.databind.JsonNode;
import com.google.auto.service.AutoService;
import lol.clann.minecraft.springboot.plugin.core.config.jackson.Jackson;
import lol.clann.minecraft.springboot.api.spi.jackson.JacksonDeserializer;
import lol.clann.minecraft.springboot.plugin.core.config.jackson.fill.BaseJsonDeserializer;
import relocate.ninja.leaping.configurate.ConfigurationNode;
import relocate.ninja.leaping.configurate.SimpleConfigurationNode;

import java.io.IOException;
import java.util.*;

/**
 *
 * @author pyz
 * @date 2019/5/3 3:05 PM
 */
@AutoService(JacksonDeserializer.class)
public class ConfigurationNodeDeserializer extends BaseJsonDeserializer<ConfigurationNode> implements JacksonDeserializer {
    @Override
    public Class getType() {
        return ConfigurationNode.class;
    }

    /**
     * 反序列化(创建)
     *
     * @param p
     * @param context
     * @return
     * @throws IOException
     * @throws JsonProcessingException
     */
    @Override
    protected ConfigurationNode create(JsonParser p, DeserializationContext context) throws IOException, JsonProcessingException {
        SimpleConfigurationNode root = SimpleConfigurationNode.root();
        JsonNode tree = Jackson.getObjectMapper().readTree(p);
        if (tree.isObject()) {
            Map map = new LinkedHashMap();
            Iterator<Map.Entry<String, JsonNode>> it = tree.fields();
            while (it.hasNext()) {
                Map.Entry<String, JsonNode> next = it.next();
                map.put(next.getKey(), Jackson.getObjectMapper().readValue(next.getValue().traverse(), ConfigurationNode.class));
            }
            root.setValue(map);
        } else if (tree.isArray()) {
            List list = new ArrayList<>();
            for (JsonNode jsonNode : tree) {
                list.add(Jackson.getObjectMapper().readValue(jsonNode.traverse(), ConfigurationNode.class));
            }
            root.setValue(list);
        } else {
            root.setValue(tree.textValue());
        }
        return root;
    }

    /**
     * 反序列化(填充)
     *
     * @param value
     * @param p
     * @param context
     * @return
     * @throws IOException
     * @throws JsonProcessingException
     */
    @Override
    protected ConfigurationNode fill(ConfigurationNode value, JsonParser p, DeserializationContext context) throws IOException, JsonProcessingException {
        ConfigurationNode newValue = create(p, context);
        value.mergeValuesFrom(newValue);
        return value;
    }
}
